package com.rayframework.common.lang3;


import com.rayframework.lang.NonNull;

import java.util.Arrays;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * 字符串工具类
 *
 * @author LiaoYuXing-Ray
 * @version 1.0
 * @createDate 2023/8/29 13:41
 **/
@SuppressWarnings("unused")
public class StringUtils {
    /**
     * 工具类中的方法都是静态方法访问的，因此将构造器私有不允许创建对象
     *
     * @author LiaoYuXing-Ray 2023/9/7 10:28
     */
    private StringUtils() {
        throw new AssertionError();
    }

    private static final int STRING_BUILDER_SIZE = 256;
    public static final String SPACE = " ";
    public static final String EMPTY = "";
    public static final String LF = "\n";
    public static final String CR = "\r";
    public static final int INDEX_NOT_FOUND = -1;
    private static final int PAD_LIMIT = 8192;

    /**
     * 将传入的多个对象连接成一个字符串，如果某个对象为空，则在连接时忽略该对象
     *
     * @param args 需要连接的字符串
     * @return java.lang.String
     * @author LiaoYuXing-Ray 2023/9/18 9:41
     **/
    public static String concat(Object... args) {
        if (args == null || args.length == 0) {
            return "";
        }
        // 使用Stream API将非空参数转换为字符串，并使用Collectors.joining()方法将这些字符串连接起来
        return Arrays.stream(args)
                .filter(Objects::nonNull)
                .map(Object::toString)
                .collect(Collectors.joining());
    }

    /**
     * 将传入的多个对象连接成一个字符串，并在每个对象之间插入指定的分隔符。
     * 如果传入的对象数组为空或长度为0，则返回空字符串
     *
     * @param delimiter 一个非空的分隔符（delimiter）
     * @param args      可变长度的对象数组
     * @return java.lang.String
     * @author LiaoYuXing-Ray 2023/9/18 9:57
     **/
    public static String concatDelimiter(@NonNull String delimiter, Object... args) {
        if (args == null || args.length == 0) {
            return "";
        }
        return Arrays.stream(args)
                .filter(Objects::nonNull)
                .map(Object::toString)
                .collect(Collectors.joining(delimiter));
    }


    /**
     * 将多个字符串参数连接起来，并在每个参数之间添加指定的分隔符、前缀和后缀。
     * 如果传入的对象数组为空或长度为0，则返回前缀+后缀
     *
     * @param delimiter 一个非空的分隔符（delimiter）
     * @param prefix    前缀
     * @param suffix    后缀
     * @param args      可变长度的对象数组
     * @return java.lang.String
     * @author LiaoYuXing-Ray 2023/9/18 9:57
     **/
    public static String concatAll(@NonNull String delimiter, @NonNull String prefix, @NonNull String suffix, Object... args) {
        // 如果参数为空或长度为0，直接返回前缀+后缀
        if (args == null || args.length == 0) {
            return prefix + suffix;
        }
        // 使用Arrays.stream()将可变参数args转换为流
        return Arrays.stream(args)
                // 过滤掉空值
                .filter(Objects::nonNull)
                // 将每个非空对象转换为字符串
                .map(Object::toString)
                // 使用Collectors.joining()方法连接字符串，并添加分隔符、前缀和后缀
                .collect(Collectors.joining(delimiter, prefix, suffix));
    }

    /**
     * 去除字符串的首尾空格
     *
     * @param str 要去除首尾空格的字符串
     * @return java.lang.String
     * @author LiaoYuXing-Ray 2023/9/18 10:17
     **/
    public static String trim(CharSequence str) {
        // 如果传入的字符串为null，直接返回null
        return null == str ? null : trim(str, 0);
        // 如果传入的字符串不为null，调用另一个重载的trim方法，从索引0开始去除首尾空格，并返回处理后的字符串
    }


    /**
     * 去除字符串两端空白字符的功能
     *
     * @param str  字符串
     * @param mode 整数值mode
     * @return java.lang.String
     * @author LiaoYuXing-Ray 2023/9/18 10:19
     **/
    public static String trim(CharSequence str, int mode) {
        if (str == null) {
            return null;
        }
        // 获取字符串的长度
        int length = str.length();
        // 定义起始位置为0
        int start = 0;
        // 定义结束位置为字符串长度
        int end = length;
        // 如果mode小于等于0，表示需要去除开头的空白字符
        if (mode <= 0) {
            // 循环判断起始位置是否为空白字符，如果是则将起始位置向后移动一位
            while (start < end && isBlankChar(str.charAt(start))) {
                ++start;
            }
        }
        // 如果mode大于等于0，表示需要去除结尾的空白字符
        if (mode >= 0) {
            // 循环判断结束位置是否为空白字符，如果是则将结束位置向前移动一位
            while (start < end && isBlankChar(str.charAt(end - 1))) {
                --end;
            }
        }
        // 如果起始位置小于等于0且结束位置大于等于字符串长度，说明整个字符串都是空白字符，直接返回原字符串
        // 否则返回去除空白字符后的子串
        return start <= 0 && end >= length ? str.toString() : str.toString().substring(start, end);

    }

    /**
     * 去除字符串数组中每个元素的首尾空格
     *
     * @param strArr 字符串数组
     * @author LiaoYuXing-Ray 2023/9/18 10:22
     **/
    public static void trim(String[] strArr) {
        if (null != strArr) {
            for (int i = 0; i < strArr.length; ++i) {
                // 获取当前索引位置的字符串
                String str = strArr[i];
                if (null != str) {
                    // 使用trim()方法去除当前字符串的首尾空格，并将结果赋值给当前索引位置的字符串
                    strArr[i] = str.trim();
                }
            }
        }
    }

    /**
     * 判断给定的整数是否表示一个空白字符。
     * Character.isWhitespace(c)：判断整数是否表示一个空白字符（如空格、制表符等）。
     * Character.isSpaceChar(c)：判断整数是否表示一个Unicode标准定义的空格字符。
     * c == 65279：判断整数是否等于常量值65279，该常量表示一个特殊的空白字符。
     * c == 8234：判断整数是否等于常量值8234，该常量也表示一个特殊的空白字符。
     * 如果满足上述任一条件，则函数返回true，表示给定的整数是一个空白字符；否则返回false。
     *
     * @param c 要检查的整数
     * @return 如果整数表示一个空白字符，则返回true；否则返回false
     * @author LiaoYuXing-Ray 2023/9/7 10:36
     */
    public static boolean isBlankChar(int c) {
        return Character.isWhitespace(c) || Character.isSpaceChar(c) || c == 65279 || c == 8234;
    }

    /**
     * 判断给定的字符序列是否为空白。
     *
     * @param str 要检查的字符序列
     * @return 如果字符序列为null、空字符串或只包含空白字符，则返回true；否则返回false。
     * @author LiaoYuXing-Ray 2023/9/7 10:34
     */
    public static boolean isBlank(CharSequence str) {
        int length;
        // 如果循环结束后没有找到非空白字符，或者str为null或长度为0，则函数返回true，表示字符序列是空白的。
        if (str != null && (length = str.length()) != 0) {
            for (int i = 0; i < length; ++i) {
                if (!isBlankChar(str.charAt(i))) {
                    return false;
                }
            }
        }
        return true;
    }



    public static boolean isAnyBlank(CharSequence... css) {
        if (!ArrayUtils.isEmpty(css)) {
            for (CharSequence cs : css) {
                if (isBlank(cs)) {
                    return true;
                }
            }
        }
        return false;
    }

    public static boolean isEmpty(CharSequence str) {
        return !hasLength(str);
    }

    public static boolean hasLength(CharSequence str) {
        return str != null && str.length() > 0;
    }

    public static boolean isNoneBlank(CharSequence... css) {
        return !isAnyBlank(css);
    }

    public static boolean isNoneEmpty(CharSequence... css) {
        return !isAnyEmpty(css);
    }

    /**
     * 判断给定的字符序列是否为非空白。
     *
     * @param str 要检查的字符序列
     * @return 返回true为非空白字符串；否则返回false。
     * @author LiaoYuXing-Ray 2023/9/7 10:34
     */
    public static boolean isNotBlank(CharSequence str) {
        return !isBlank(str);
    }

    public static boolean isNotEmpty(CharSequence cs) {
        return !isEmpty(cs);
    }

    public static boolean isNumeric(CharSequence cs) {
        if (isEmpty(cs)) {
            return false;
        } else {
            int sz = cs.length();

            for(int i = 0; i < sz; ++i) {
                if (!Character.isDigit(cs.charAt(i))) {
                    return false;
                }
            }

            return true;
        }
    }

    public static boolean isNumericSpace(CharSequence cs) {
        if (cs == null) {
            return false;
        } else {
            int sz = cs.length();

            for(int i = 0; i < sz; ++i) {
                if (!Character.isDigit(cs.charAt(i)) && cs.charAt(i) != ' ') {
                    return false;
                }
            }

            return true;
        }
    }

    public static boolean isWhitespace(CharSequence cs) {
        if (cs == null) {
            return false;
        } else {
            int sz = cs.length();

            for(int i = 0; i < sz; ++i) {
                if (!Character.isWhitespace(cs.charAt(i))) {
                    return false;
                }
            }

            return true;
        }
    }

    public static boolean isAnyEmpty(CharSequence... css) {
        if (!ArrayUtils.isEmpty(css)) {
            for (CharSequence cs : css) {
                if (isEmpty(cs)) {
                    return true;
                }
            }
        }
        return false;
    }


    public static String deleteWhitespace(String str) {
        if (isEmpty(str)) {
            return str;
        } else {
            int sz = str.length();
            char[] chs = new char[sz];
            int count = 0;

            for(int i = 0; i < sz; ++i) {
                if (!Character.isWhitespace(str.charAt(i))) {
                    chs[count++] = str.charAt(i);
                }
            }

            if (count == sz) {
                return str;
            } else {
                return new String(chs, 0, count);
            }
        }
    }


    public static boolean contains(CharSequence seq, CharSequence searchSeq) {
        if (seq != null && searchSeq != null) {
            return CharSequenceUtils.indexOf(seq, searchSeq, 0) >= 0;
        } else {
            return false;
        }
    }

    public static boolean contains(CharSequence seq, int searchChar) {
        if (isEmpty(seq)) {
            return false;
        } else {
            return CharSequenceUtils.indexOf(seq, searchChar, 0) >= 0;
        }
    }
}

